/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.utils;

import org.eclipse.draw2d.geometry.Point;

import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;

/**
 * 
 * 
 * @author Patrick Tessier
 * @since 8 sept. 06
 * 
 * This class is used to calculate director vector of a link
 */
public  class VectorCalculus {
	
	/**
	 * this is the channel of debug
	 */
	private static int channel=24;
	/**
	 * this is a constant of the small distance
	 */
	private static int SMALLDISTANCE=20;
	
	/**
	 * this is a constant of the normal distance (in pixel)
	 */
	private static int DISTANCE=40;
	
	
	/**this is constant of the a big distance 60 pixels
	 * 
	 */
	private static int BIGDISTANCE=60;
	
	/**
	 * 
	 * This method allows calulatin the vector director betwen 2 graphNodes
	 * @param target the GraphNode source
	 * @param source  the GraphNode target
	 *
	 * @return the vector director
	 */
	public static Point calculate(GraphNode source,GraphNode target ){
		Point vector=new Point();
		double x=target.getPosition().x-source.getPosition().x;
		double y=target.getPosition().y-source.getPosition().y;
		double length= Math.sqrt(Math.pow(x, 2)+Math.pow(y, 2));
		x=x/length;
		y=y/length;
		vector.x=new Integer(""+Math.round(x)).intValue();
		vector.y=new Integer(""+Math.round(y)).intValue();
		
		
		return vector;
	}
	
	/**
	 * Calculate a precise Vector director of a link.
	 * 
	 * @param target point of the target
	 * @param source point of the source
	 * 
	 * @return the vector director
	 */
	public static double calculateAngle(Point source,Point target ){
		Point vector=new Point();
		double x=target.x-source.x;
		double y=target.y-source.y;
		
		double angle= Math.atan2(y, x);
		
		return angle;
		
	}
	
	
	
	/**
	 * 
	 * this method is used to set all label of an association a a good position
	 * @param edge that represent the association
	 * @param target the graphNode target
	 * @param source  the graphNode source
	 */
	public static void setGoodPositionForAssociation(GraphEdge edge,GraphNode source,GraphNode target){
		//dependency contains two labels
		Point vector =VectorCalculus.calculate(source, target);
		Debug.debug(null, "Vector "+ vector,channel );
		if ((vector.x==0) && (vector.y==1)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(VectorCalculus.BIGDISTANCE,0)); //name
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,-VectorCalculus.SMALLDISTANCE)); //target role1
			((GraphNode)edge.getContained().get(2)).setPosition(new Point(-VectorCalculus.BIGDISTANCE,VectorCalculus.SMALLDISTANCE)); //source role2
			((GraphNode)edge.getContained().get(3)).setPosition(new Point(-VectorCalculus.DISTANCE,-VectorCalculus.SMALLDISTANCE)); //target mult1
			((GraphNode)edge.getContained().get(4)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,VectorCalculus.SMALLDISTANCE)); //source mult2
			((GraphNode)edge.getContained().get(5)).setPosition(new Point(VectorCalculus.BIGDISTANCE,-VectorCalculus.SMALLDISTANCE)); //stereo
		}
		if ((vector.x==0) && (vector.y==-1)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(0,0)); //name
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,VectorCalculus.SMALLDISTANCE)); //targetrole1
			((GraphNode)edge.getContained().get(2)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,-VectorCalculus.SMALLDISTANCE)); //source role2
			((GraphNode)edge.getContained().get(3)).setPosition(new Point(-VectorCalculus.DISTANCE,VectorCalculus.SMALLDISTANCE)); //target mult1
			((GraphNode)edge.getContained().get(4)).setPosition(new Point(-VectorCalculus.DISTANCE,-VectorCalculus.SMALLDISTANCE)); //source mult2
			((GraphNode)edge.getContained().get(5)).setPosition(new Point(VectorCalculus.BIGDISTANCE,VectorCalculus.SMALLDISTANCE)); //stereo
		}
		if ((vector.x==1) && (vector.y==0)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(0,VectorCalculus.SMALLDISTANCE)); //name
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(-VectorCalculus.BIGDISTANCE,VectorCalculus.SMALLDISTANCE)); //targety role1
			((GraphNode)edge.getContained().get(2)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,-VectorCalculus.SMALLDISTANCE)); //source role2
			((GraphNode)edge.getContained().get(3)).setPosition(new Point(-VectorCalculus.BIGDISTANCE,-VectorCalculus.SMALLDISTANCE)); //target mult1
			((GraphNode)edge.getContained().get(4)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,VectorCalculus.SMALLDISTANCE)); //source mult2
			((GraphNode)edge.getContained().get(5)).setPosition(new Point(0,-VectorCalculus.SMALLDISTANCE)); //stereo
		}
		if ((vector.x==-1) && (vector.y==0)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(0,VectorCalculus.SMALLDISTANCE)); //name
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,-VectorCalculus.SMALLDISTANCE)); //target role1
			((GraphNode)edge.getContained().get(2)).setPosition(new Point(-VectorCalculus.BIGDISTANCE,VectorCalculus.SMALLDISTANCE)); //sourcerole2
			((GraphNode)edge.getContained().get(3)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,VectorCalculus.SMALLDISTANCE)); //target mutl1
			((GraphNode)edge.getContained().get(4)).setPosition(new Point(-VectorCalculus.BIGDISTANCE,-VectorCalculus.SMALLDISTANCE)); //source mult2
			((GraphNode)edge.getContained().get(5)).setPosition(new Point(0,-VectorCalculus.SMALLDISTANCE)); //stereo
		}
		if ((vector.x==1) && (vector.y==1)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(0,VectorCalculus.SMALLDISTANCE)); //name
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(-VectorCalculus.DISTANCE,-VectorCalculus.BIGDISTANCE)); //target role1
			((GraphNode)edge.getContained().get(2)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,VectorCalculus.BIGDISTANCE)); //source role2
			((GraphNode)edge.getContained().get(3)).setPosition(new Point(-VectorCalculus.SMALLDISTANCE,VectorCalculus.SMALLDISTANCE)); //target mutl1
			((GraphNode)edge.getContained().get(4)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,-VectorCalculus.SMALLDISTANCE)); //source mult2
			((GraphNode)edge.getContained().get(5)).setPosition(new Point(VectorCalculus.DISTANCE,0)); //stereo
		}
		if ((vector.x==-1) && (vector.y==1)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(VectorCalculus.BIGDISTANCE,VectorCalculus.SMALLDISTANCE)); //name
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,-VectorCalculus.BIGDISTANCE)); //target role1
			((GraphNode)edge.getContained().get(2)).setPosition(new Point(-VectorCalculus.BIGDISTANCE,-VectorCalculus.SMALLDISTANCE)); //sourcerole2
			((GraphNode)edge.getContained().get(3)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,VectorCalculus.SMALLDISTANCE)); //targetmutl1
			((GraphNode)edge.getContained().get(4)).setPosition(new Point(-VectorCalculus.SMALLDISTANCE,VectorCalculus.SMALLDISTANCE)); //sourcemult2
			((GraphNode)edge.getContained().get(5)).setPosition(new Point(0,-VectorCalculus.SMALLDISTANCE)); //stereo
		}
		if ((vector.x==1) && (vector.y==-1)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(0,0)); //name
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(-VectorCalculus.BIGDISTANCE,-VectorCalculus.SMALLDISTANCE)); //target role1
			((GraphNode)edge.getContained().get(2)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,0)); //source role2
			((GraphNode)edge.getContained().get(3)).setPosition(new Point(-VectorCalculus.BIGDISTANCE,VectorCalculus.SMALLDISTANCE)); //target mutl1
			((GraphNode)edge.getContained().get(4)).setPosition(new Point(0,-VectorCalculus.DISTANCE)); //source mult2
			((GraphNode)edge.getContained().get(5)).setPosition(new Point(VectorCalculus.BIGDISTANCE,-VectorCalculus.SMALLDISTANCE)); //stereo
		}
		if ((vector.x==-1) && (vector.y==-1)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(VectorCalculus.BIGDISTANCE,0)); //name
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,VectorCalculus.BIGDISTANCE)); //target role1
			((GraphNode)edge.getContained().get(2)).setPosition(new Point(-VectorCalculus.DISTANCE,-VectorCalculus.DISTANCE)); //source role2
			((GraphNode)edge.getContained().get(3)).setPosition(new Point(VectorCalculus.SMALLDISTANCE,-VectorCalculus.SMALLDISTANCE)); //target mutl1
			((GraphNode)edge.getContained().get(4)).setPosition(new Point(-VectorCalculus.SMALLDISTANCE,VectorCalculus.SMALLDISTANCE)); //source mult2
			((GraphNode)edge.getContained().get(5)).setPosition(new Point(0,-VectorCalculus.SMALLDISTANCE)); //stereo
		}
	}
	
	/**
	 * 
	 * This method is used to set all label of an extension a a good position
	 * @param edge that represent the association
	 * @param target the graphNode target
	 * @param source  the graphNode source
	 */
	public static void setGoodPositionForExtension(GraphEdge edge,GraphNode source,GraphNode target){
		//dependency contains two labels
		Point vector =VectorCalculus.calculate(source, target);
		if ((vector.x==0) && (vector.y==1)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(VectorCalculus.BIGDISTANCE,0)); //name
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(-VectorCalculus.BIGDISTANCE,VectorCalculus.SMALLDISTANCE)); //role2	
		}
		if ((vector.x==0) && (vector.y==-1)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(VectorCalculus.BIGDISTANCE,0)); //name	
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(VectorCalculus.DISTANCE,-VectorCalculus.SMALLDISTANCE)); //role2	
		}
		if ((vector.x==1) && (vector.y==0)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(0,VectorCalculus.SMALLDISTANCE)); //name
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(VectorCalculus.DISTANCE,-VectorCalculus.DISTANCE)); //role2	
		}
		if ((vector.x==-1) && (vector.y==0)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(0,VectorCalculus.SMALLDISTANCE)); //name
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(-VectorCalculus.BIGDISTANCE,VectorCalculus.SMALLDISTANCE)); //role2
		}
		if ((vector.x==1) && (vector.y==1)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(VectorCalculus.DISTANCE,-VectorCalculus.SMALLDISTANCE)); //name
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(-VectorCalculus.BIGDISTANCE,VectorCalculus.SMALLDISTANCE)); //role2
		}
		if ((vector.x==-1) && (vector.y==1)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(VectorCalculus.BIGDISTANCE,VectorCalculus.SMALLDISTANCE)); //name			
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(-VectorCalculus.BIGDISTANCE,-VectorCalculus.DISTANCE)); //role2		
		}
		if ((vector.x==1) && (vector.y==-1)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(VectorCalculus.BIGDISTANCE,0)); //name			
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(VectorCalculus.DISTANCE,VectorCalculus.SMALLDISTANCE)); //role2			
		}
		if ((vector.x==-1) && (vector.y==-1)){
			((GraphNode)edge.getContained().get(0)).setPosition(new Point(VectorCalculus.BIGDISTANCE,0)); //name
			((GraphNode)edge.getContained().get(1)).setPosition(new Point(0,-VectorCalculus.DISTANCE)); //role2
		}
	}

}
